package stamboom;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.*;

public class Administratie {

    //************************datavelden*************************************
    private ArrayList<Persoon> personen;
    private int nextGezinsNr;
    private int nextPersNr;

    //***********************constructoren***********************************
    /**
     * er wordt een administratie gecreeerd met 0 personen en dus 0 gezinnen
     * personen en gezinnen die in de toekomst zullen worden gecreeerd, worden
     * elk opvolgend genummerd vanaf 1.
     */
    public Administratie() {
        this.personen = new ArrayList<>();
        this.nextGezinsNr = 1;
        this.nextPersNr = 1;
    }

    /**
     * er wordt een Administratie gecreëerd en gevuld aan de hand van de
     * gegevens in het bestand met de naam naamBron
     *
     * @param naamBron een geserialiseerd objectbestand met persoonsgegevens,
     * gevolgd door de 2 getallen die resp. betrekking hebben op een
     * eerstvolgend persoonsnummer en gezinsnummer
     */
    public Administratie(String naamBron) throws IOException,
            ClassNotFoundException {
        try {
            FileInputStream fileIn = new FileInputStream(naamBron);
            ObjectInputStream in = new ObjectInputStream(fileIn);
            this.personen = (ArrayList<Persoon>) in.readObject();
            this.nextPersNr = (int) in.readObject();
            this.nextGezinsNr = (int) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException e) {
            System.out.println(e.toString());
        }

    }

    //**********************methoden****************************************
    /**
     * er wordt een persoon met een gegeven geslacht, met als voornamen vnamen,
     * achternaam anaam, tussenvoegsel tvoegsel, geboortedatum gebdat en een
     * gegeven ouderlijk gezin; de persoon krijgt een uniek nummer toegewezen de
     * creatie van deze persoon is voortaan ook bij het ouderlijk gezin bekend.
     * Alleen de parameter ouderlijkGezin mag de waarde null hebben.
     */
    public void addPersoon(Geslacht geslacht, String[] vnamen, String anaam,
            String tvoegsel, GregorianCalendar gebdat, Gezin ouderlijkGezin) {
        /**
         * Check if only ouderlijkGezin equals null
         */
        if (geslacht == null || vnamen == null || anaam == null || tvoegsel
                == null || gebdat == null) {
            throw new RuntimeException("One or more values are null that should"
                    + "not be null.");
        } else {

            /**
             * Note: This for construct makes it so that all names that are
             * entered have valid casing. Something that wasn't mentioned in the
             * assignment, but is checked for by the test cases.
             */
            for (int i = 0; i < vnamen.length; i++) {
                String tName = vnamen[i].toLowerCase();

                String tCName = Character.toString(tName.charAt(0))
                        .toUpperCase();
                String rString = tCName + tName.substring(1);
                vnamen[i] = (rString);
            }
            String tempAnaam = anaam.toLowerCase();
            tempAnaam = Character.toString(tempAnaam.charAt(0)).toUpperCase()
                    + tempAnaam.substring(1);
            Persoon p = new Persoon(nextPersNr, vnamen, anaam, tvoegsel,
                    gebdat, geslacht, ouderlijkGezin);
            personen.add(p);
            nextPersNr++;
            if (ouderlijkGezin != null) {
                ouderlijkGezin.breidUitMet(p);
            }
        }
    }

    /**
     * er wordt een (kinderloos) gezin met m1 en m2 als ouders gcreeerd; de
     * huwelijks- en scheidingsdatum zijn onbekend (null); het gezin krijgt een
     * uniek nummer toegewezen
     */
    public void addGezin(Persoon m1, Persoon m2) {
        // gecreeerd object wordt niet aan variabele gekoppeld; zie code
        // constructor van de klasse Gezin:
        new Gezin(nextGezinsNr, m1, m2);
        nextGezinsNr++;
    }

    /**
     *
     * @param nr
     * @return de persoon met nummer nr, als die niet bekend is wordt er null
     * geretourneerd
     */
    public Persoon getPersoon(int nr) {
        for (Persoon p : personen) {
            if (p.getNr() == nr) {
                return p;
            }
        }
        return null;
    }

    /**
     * @return alle personen met een achternaam gelijk aan de meegegeven
     * achternaam
     */
    public ArrayList<Persoon> getPersonen(String achternaam) {
        ArrayList<Persoon> rList = new ArrayList<>();
        for (Persoon p : personen) {
            if (p.getAchternaam().equalsIgnoreCase(achternaam)) {
                rList.add(p);
            }
        }
        return rList;
    }

    /**
     *
     * @param gezinsNr
     * @return het gezin met nummer nr. Als dat niet bekend is wordt er null
     * geretourneerd
     */
    public Gezin getGezin(int gezinsNr) {
        // inefficiente oplossing
        for (Persoon p : personen) {
            Iterator<Gezin> it = p.getGezinnen();
            while (it.hasNext()) {
                Gezin r = it.next();
                if (r.getNr() == gezinsNr) {
                    return r;
                }
            }
        }
        return null;
    }

    /**
     * de persoonsgegevens worden weggeschreven in een geserialiseerd bestand
     * met de naam naamBestemming, eerst worden de persoonsgegevens
     * weggeschreven en vervolgens het eerstvolgende nieuwe persoonsnummer
     * gevolgd door het nieuwe relatienummer
     *
     * @param naamBestemming
     */
    public void save(String naamBestemming) throws FileNotFoundException,
            IOException {
        try {
            File myFile = new File(naamBestemming + ".ser");
            if (!myFile.exists()) {
                myFile.createNewFile();
            }
            FileOutputStream newStream =
                    new FileOutputStream(myFile, false);
            ObjectOutputStream out = new ObjectOutputStream(newStream);
            out.writeObject(this.personen);
            out.writeObject(this.nextPersNr);
            out.writeObject(this.nextGezinsNr);
            out.close();
            newStream.close();
        } catch (IOException e) {
            System.out.println(e.toString());
        }

    }

    public Iterator getAllePersonen() {
        return personen.iterator();
    }

    public Iterator<Gezin> gezinnen() {

        // inefficiente oplossing

        ArrayList<Gezin> gezinnen = new ArrayList<>();

        for (Persoon persoon : personen) {

            Iterator<Gezin> it = persoon.getGezinnen();

            while (it.hasNext()) {

                Gezin g = it.next();

                if (!gezinnen.contains(g)) {

                    gezinnen.add(g);

                }

            }

        }

        return gezinnen.iterator();

    }
}